#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/input/mt.h>
#include <linux/input.h>
#include <linux/irqreturn.h>
#include <linux/of_gpio.h>
#include "../../init-input.h"



#define CTP_NAME "bl7401"
#define CTP_IRQ_MODE (IRQF_TRIGGER_FALLING)

#define TOUCH_EVENT_DOWN 0x00 /* 按下 */
#define TOUCH_EVENT_UP 0x01 /* 抬起 */
#define TOUCH_EVENT_ON 0x02 /* 移动 */
#define TOUCH_EVENT_RESERVED 0x03 /* 保留 */


//struct btl_touch_pad_info {
//	u8 gestureCode;	
//	u8 key_num;
//	u8 event_flag:2;
//	u16 x:14;
//	u8 id:4;
//	u16 y:12;
//};

//struct ctp_config_info config_info = {
//	.input_type = CTP_TYPE,
//	.name = NULL,
//};


//static int startup(void)
//{
//    int ret = 0;
//   printk("GTP driver init func = %s,line = %d \n", __func__, __LINE__);
//	if (!input_sensor_startup(&(config_info.input_type))) {
//		ret = input_sensor_init(&(config_info.input_type));
//		if (ret != 0) {
//			pr_err("%s:ctp_ops.input_sensor_init err.\n", __func__);
//			return -1;
//		}
//		input_set_power_enable(&(config_info.input_type), 1);
//	} else {
//		pr_err("%s: input_ctp_startup err.\n", __func__);
//		return -1;
//	}
//    return 1;

//}


static const struct regmap_config regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
    .max_register = 0x68,
};

struct bl7401_data{
    struct input_dev *input;
    struct i2c_client *client;
    struct regmap	*regmap;
    int irq_gpio;
    struct mutex i2c_lock;	
//    struct btl_touch_pad_info info;
};


//typedef struct {
//    u8 code;
//    u8 num;
//    u16 PosX;
//    u16 PosY;
//    u8 PosID;
//    u8 Event;
//} ctp_data;
//ctp_data st[10] = {0};


//static int ctp_bl7401_bl_read(struct bl7401_data *bl, u8 addr, u8 *buf, u16 len)
//{
//    struct i2c_client *client = bl->client;
//    struct i2c_msg msg[2];
//    int ret;

//    msg[0].flags = 0; /* i2c 写 */
//    msg[0].addr = client->addr;
//    msg[0].buf = &addr;
//    msg[0].len = 1; /* 1 个字节 */

//    msg[1].flags = I2C_M_RD; /* i2c 读 */
//    msg[1].addr = client->addr;
 //   msg[1].buf = buf;
 ////   msg[1].len = len;

//    ret = i2c_transfer(client->adapter, msg, 2);
//    if (2 == ret)
//        return 0;
//    else {
//        dev_err(&client->dev, "%s: read error, addr=0x%x len=%d.\n", __func__, addr, len);
//        return -1;
//    }
//}


static void btl_touch_down(struct bl7401_data* ts,s32 id,s32 x,s32 y,s32 w, s8 pressure)
{
    input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
    input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 1);
	input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1);
    input_report_abs(ts->input, ABS_MT_POSITION_X, x);
    input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
    input_report_key(ts->input, BTN_TOUCH, 1);
    input_mt_sync(ts->input);
}


static void btl_touch_up(struct bl7401_data* ts, s32 id, s32 x,s32 y)
{

//    input_mt_slot(ts->input, id);
//    input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false);

}


static void bl7401_update_data(struct bl7401_data *bl)
{
	u8 point_data[62] = {0};
    int ret;
    u8  touch_num = 0;
	u8  pressure = 0x0;
    s32 input_x = 0;
    s32 input_y = 0;
    s32 id = 0;
    u8  eventFlag = 0;
    int i;


	ret = regmap_bulk_read(bl->regmap, 0x01, &point_data, 62);
    if (ret < 0) {
        printk("use I2C reading time from RTC failed with err:%d\n", ret);
        goto exit_work_func;
    }

    touch_num = point_data[1] & 0x0f;
    if ((touch_num > 10) || (touch_num == 0))
    {
        goto exit_work_func;
    }


    for (i = 0; i < 10; i++)
	{
		eventFlag = point_data[2 + 6 * i] >> 6; 	        
		id = point_data[4 + 6 * i] >> 4;
		input_x  = ((point_data[2 + 6 * i] & 0x0f) << 8) | point_data[3 + 6 * i];
		input_y  = ((point_data[4 + 6 * i] & 0x0f) << 8) | point_data[5 + 6 * i];

        
	    if((id!=0x0f)&&((eventFlag == TOUCH_EVENT_ON) || (eventFlag == TOUCH_EVENT_DOWN)))
        {
//            btl_touch_down(bl, id, input_x, input_y, 1, pressure);			
            btl_touch_down(bl, id, 1200 - input_y, input_x, 1, pressure);
			printk("eventFlag:%d, id:%d, x:%d, y:%d", eventFlag, id, input_x, input_y);
         }
		else if(eventFlag == TOUCH_EVENT_UP)
        {
            btl_touch_up(bl, id, input_x, input_y);
        }
	}

    input_sync(bl->input);
	return;


exit_work_func:
    input_report_key(bl->input, BTN_TOUCH, 0);
    input_sync(bl->input);
	return;
	
}



/*中断函数*/
static irqreturn_t bl7401_handler(int irq, void *dev_id)
{


    struct bl7401_data *bl = (struct bl7401_data*)dev_id;

    /*线程化加锁*/
    mutex_lock(&bl->i2c_lock);
	bl7401_update_data(bl);
	mutex_unlock(&bl->i2c_lock);
	return IRQ_HANDLED;
}

static int bl7401_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    struct bl7401_data *bl;

    //config_info.node = client->dev.of_node;
    /*申请空间*/
    bl = devm_kzalloc(&client->dev, sizeof(*bl), GFP_KERNEL);
    if(!bl)
    {
        dev_err(&client->dev, "device memory request failed\n");
		return -ENOMEM;
    }

    bl->regmap = devm_regmap_init_i2c(client, &regmap_config);
	if (IS_ERR(bl->regmap)) 
    {
		dev_err(&client->dev, "I2C initialization regmap failed\n");
		return PTR_ERR(bl->regmap);
	}

    i2c_set_clientdata(client, bl);

    mutex_init(&bl->i2c_lock);
    /*AW 初始化IC，引脚，上电*/
//    if (!startup()) 
//    {
//		printk("can not startup device!\n");
//        return -1;
//    }



    printk("starus  request irq\n");
    bl->irq_gpio = of_get_named_gpio(client->dev.of_node, "ctp_int_port", 0);
    if (!gpio_is_valid(bl->irq_gpio)) 
    {
            printk("Failed to get bl interrupt gpio\n");
            return bl->irq_gpio;
    }


//    ret = devm_gpio_request_one(&client->dev, bl->irq_gpio, GPIOF_IN, "bl7401_interrupt");
	ret = gpio_request(bl->irq_gpio, "bl7401_interrupt");
    if (ret < 0)
    {
        printk("request gpio fiiled\n");
        return ret;
    }
	gpio_direction_input(bl->irq_gpio);
	
    ret = devm_request_threaded_irq(&client->dev, gpio_to_irq(bl->irq_gpio), NULL, bl7401_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, bl);
    if (ret < 0)
    {
        printk("Failed to request touchscreen IRQ.\n");
        return ret;
    }

//    ret = devm_request_irq(&client->dev, gpio_to_irq(bl->irq_gpio),  bl7401_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, bl);
//    if (ret < 0)
//    {
//        printk("Failed to request touchscreen IRQ.\n");
//        return ret;
//    }

    /*ME input设备申请与初始化*/
    bl->client = client;
    bl->input = devm_input_allocate_device(&client->dev);
    if (bl->input == NULL) 
    {
        printk("Failed to allocate input device.\n");
        return -1;
    }

//    bl->input->name = "bl7401"; 
//    bl->input->id.bustype = BUS_I2C;
//    input_set_abs_params(bl->input, ABS_MT_POSITION_X, 0, 1200, 0, 0);
//    input_set_abs_params(bl->input, ABS_MT_POSITION_Y, 0, 1920, 0, 0);
//    ret = input_mt_init_slobl(bl->input, 10, INPUT_MT_DIRECT);
//    if (ret) 
//    {
//        printk( "Failed to init MT slobl.\n");
//        return ret;
//    }
    bl->input->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    bl->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    __set_bit(INPUT_PROP_DIRECT, bl->input->propbit);

    input_set_abs_params(bl->input, ABS_MT_POSITION_X, 0, 1200, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_POSITION_Y, 0, 1920, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_TRACKING_ID, 0, 10, 0, 0);

    bl->input->name = "betterlife-ts";
    bl->input->phys = "input/ts";
    bl->input->id.bustype = BUS_I2C;
    bl->input->id.vendor = 0xDEAD;
    bl->input->id.product = 0xBEEF;
    bl->input->id.version = 10427;
    /*注册 input_dev */
    ret = input_register_device(bl->input);
    if(ret)
        return ret;

    return 0;
}

static int bl7401_remove(struct i2c_client *client)
{
    struct bl7401_data *bl = i2c_get_clientdata(client);
    input_unregister_device(bl->input);
	gpio_free(bl->irq_gpio);
    return 0;
}

static const struct of_device_id bl7401_of_match[] = {
	{.compatible = "bl7401"},
	{},
};

static struct i2c_driver bl7401_driver = {
	.probe = bl7401_probe,
	.remove = bl7401_remove,
	.driver = {
        .name = CTP_NAME,
		.owner = THIS_MODULE,
		.of_match_table = bl7401_of_match,
    }
};  

static int __init bl7401_init(void)
{
    printk("bl7401 driver init func\n");
	i2c_add_driver(&bl7401_driver);
    return 0;
}

static void __exit bl7401_exit(void)
{
	printk("bl7401 driver exited\n");
	i2c_del_driver(&bl7401_driver);
}


late_initcall(bl7401_init);
module_exit(bl7401_exit);


MODULE_LICENSE("GPL");
